﻿using System;
using PropertyExpression.ControllableQuery;

namespace ConsoleApplication2
{
    internal class Program
    {
        private static void Main()
        {
            Console.Write("BillOfMaterialsHeaderId=");
            var billOfMaterialsHeaderId = Console.ReadLine();
            Console.Write("ModelPublicationId=");
            var modelPublicationId = Console.ReadLine();
            Console.Write("ServicePartsPageId=");
            var servicePartsPageId = Console.ReadLine();
            Console.Write("RedCondition=");
            var redCondition = bool.Parse(Console.ReadLine());

            foreach (var record in QExecutor.MaterializeReader(
                context => {
                    RedSwitch redSwitch;
                    if (redCondition)
                    {
                        Console.Write("BlueCondition=");
                        var blueCondition = Console.ReadLine();
                        Console.Write("LanguageCode=");
                        var languageCode = Console.ReadLine();
                        Console.Write("ModelId=");
                        var modelId = int.Parse(Console.ReadLine());
                        redSwitch = new RedSwitch.On(
                            bool.Parse(blueCondition), context.Param(languageCode), context.Param(modelId));
                    }
                    else
                        redSwitch = new RedSwitch.Off();
                    return new {
                                   billOfMaterialsHeaderId = context.Param(() => int.Parse(billOfMaterialsHeaderId)),
                                   modelPublicationId = context.Param(() => int.Parse(modelPublicationId)),
                                   servicePartsPageId = context.Param(() => int.Parse(servicePartsPageId)),
                                   redSwitch
                               };
                },
                p => {
                    var q = new Q(@"
FROM    BillOfMaterialsLine
WHERE   BillOfMaterialsHeaderId = ")._(p.billOfMaterialsHeaderId)._(@"
        AND ( ( BillOfMaterialsLine.MainLinkExcludedFrom = 0
                AND EXISTS ( SELECT 1
                             FROM   MainPartLink
                             WHERE  MainPartLink.PartNumber = BillOfMaterialsLine.PartNumber
                                    AND MainPartLink.ModelPublicationId = ")._(p.modelPublicationId)._(@"
                                    AND MainPartLink.ServicePartsPageId <> ")._(p.servicePartsPageId)._(@" )
              )");
                    p.redSwitch.Match(
                        on => {
                            q._(@"
              OR ( BillOfMaterialsLine.InnerLinkExcludedFrom = 0
                   AND EXISTS ( SELECT  1
                                FROM    InnerPartLink
                                        INNER JOIN Model
                                            ON InnerPartLink.ModelCode = Model.ModelCode
                                               AND InnerPartLink.ModelSequence = Model.ModelSequence");
                            if (on.BlueCondition)
                                q._(@"
                                        INNER JOIN Publication
                                            ON InnerPartLink.PublicationId = Publication.PublicationId");
                            q._(@"
                                        INNER JOIN LocalizedPublication
                                            ON InnerPartLink.PublicationId = LocalizedPublication.PublicationId
                                               AND LocalizedPublication.LanguageCode = ")._(on.LanguageCode)._(@"
                                WHERE   InnerPartLink.PartNumber = BillOfMaterialsLine.PartNumber
                                        AND Model.ModelId = ")._(on.ModelId);
                            if (on.BlueCondition)
                                q._(@"
                                        AND Publication.FollowingPublicationId IS NULL");
                            q._(@" )
                 )");
                        },
                        off => { });
                    q._(@"
            )");
                    return q.Select(_ => new {
                                                 BillOfMaterialsLineId = _.Int(),
                                                 PartNumber = _.String()
                                             });
                }))
            {
                Console.WriteLine(
                    "BillOfMaterialsLineId = {0}, PartNumber = {1}",
                    record.BillOfMaterialsLineId,
                    record.PartNumber);
            }
        }

        internal abstract class RedSwitch
        {
            public class On : RedSwitch
            {
                public readonly bool BlueCondition;
                public readonly IParam<string> LanguageCode;
                public readonly IParam<int> ModelId;

                public On(bool blueCondition, IParam<string> languageCode, IParam<int> modelId)
                {
                    BlueCondition = blueCondition;
                    LanguageCode = languageCode;
                    ModelId = modelId;
                }

                public override void Match(Action<On> on, Action<Off> off)
                {
                    on(this);
                }
            }

            public class Off : RedSwitch
            {
                public override void Match(Action<On> on, Action<Off> off)
                {
                    off(this);
                }
            }

            public abstract void Match(Action<On> on, Action<Off> off);
        }
    }
}